﻿using Ionic.Zip;
using JiveMessenger.Utilities;
using NLog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Xml;

namespace JiveMessenger.Misc
{
    public class Updater
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        private static readonly string[] _updateUrls = new string[] { "https://dl.dropboxusercontent.com/u/527098/jive_version.xml", "http://JiveMessenger.co.vu/JiveMessenger/jive_version.xml" };





        public static event EventHandler<UpdateCompletedEventArgs> UpdateCompleteEvent;
        public static event EventHandler<UpdateDownloadProgressEventArgs> UpdateDownloadProgressChanged;
        public string VersionNumber { get; set; }
        public string DownloadUrl { get; set; }

        /// <summary>
        /// Fetches the latest version info. Returns null in case of error.
        /// </summary>
        /// <returns></returns>
        public static Updater GetLatestVersion()
        {
            foreach (string versionUrl in _updateUrls)
            {
                Updater up = new Updater();
                byte[] data = null;
                //string CacheDir = "";
                //Application.Current.Dispatcher.Invoke(() =>
                //    {
                //        CacheDir = StaticMethods.CombinePath(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.Current.GetType().Assembly.GetName().Name);
                //    });
                //if (!Directory.Exists(CacheDir)) Directory.CreateDirectory(CacheDir);
                //string cache = Path.Combine(CacheDir ,"update.xml");
                //File.Delete(cache);
                TimeoutWebClient cli = new TimeoutWebClient(10000)
                {
                    Proxy = null
                };

                try
                {
                    data = cli.DownloadData(versionUrl);
                }
                catch (Exception e)
                {
                    Logger.ErrorException("Error downloading update check: ", e);
                    return null;
                }
                finally
                {
                    cli.Dispose();
                }

                if (data != null)
                {
                    using (MemoryStream stream = new MemoryStream(data))
                    {
                        XmlDocument xml = new XmlDocument();
                        xml.Load(stream);

                        XmlNodeList nodes = xml.GetElementsByTagName("JiveMessenger");
                        foreach (XmlNode node in nodes)
                        {
                            string versionNodeText = "Versionx86";
                            string downloadNodeText = "DownloadUrlx86";

                            XmlNode versionNode = node.SelectSingleNode(versionNodeText);
                            if (versionNode != null)
                            {
                                up.VersionNumber = versionNode.InnerText;
                            }
                            XmlNode urlNode = node.SelectSingleNode(downloadNodeText);
                            //foreach (XmlNode n in urlNodes)
                            //{
                            if (urlNode != null)
                                up.DownloadUrl = urlNode.InnerText;
                            //}
                        }
                        return up;
                    }
                }
            }
            return null;
        }
        /// <summary>
        /// Downloads and unpacks update async
        /// </summary>
        /// <param name="downloadUrl"></param>
        public static void DownloadUpdate(string downloadUrl)
        {
            Task t = Task.Factory.StartNew(() =>
            {


                //Application.Current.Dispatcher.Invoke(() =>
                //{
                //    CacheDir = StaticMethods.CombinePath(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.Current.MainWindow.GetType().Assembly.GetName().Name);
                //});
                //string UpdateCache = StaticMethods.CombinePath(CacheDir, "update.zip");
                //File.Delete(UpdateCache);
                using (WebClient cli = new WebClient { Proxy = null })
                {
                    string url = Uri.EscapeUriString(downloadUrl);
                    cli.DownloadProgressChanged += cli_DownloadProgressChanged;
                    cli.DownloadDataCompleted += cli_DownloadDataCompleted;
                    cli.DownloadDataAsync(new Uri(url));

                }
                //int tries = 0;
                //while (true)
                //{
                //    if (!StaticMethods.FileIsLocked(UpdateCache) || tries > 100)
                //    {
                //        break;
                //    }
                //    Thread.Sleep(50);
                //    tries++;

                //}

            });
        }

        static void cli_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            var data = e.Result;
            bool success = false;
            string error = "";
            if(!e.Cancelled && e.Error==null)
            {
                using (Stream fileStream = new MemoryStream(data))
                {
                    if (fileStream != null)
                    {
                        using (ZipFile zipFile = ZipFile.Read(fileStream))
                        {
                            Dictionary<string, string> files = new Dictionary<string, string>();
                            try
                            {
                                foreach (ZipEntry entry in zipFile)
                                {
                                    string oldName = Path.GetFileNameWithoutExtension(entry.FileName) + Path.GetExtension(entry.FileName) + ".OldJiveFile";
                                    if (File.Exists(oldName))
                                        File.Delete(oldName);
                                    if (File.Exists(entry.FileName))
                                        File.Move(entry.FileName, oldName);
                                    string fileName = entry.FileName;
                                    files.Add(oldName, fileName);

                                    using (FileStream stream = File.OpenWrite(fileName))
                                    {
                                        entry.Extract(stream);
                                        success = true;
                                    }
                                }
                            }
                            catch (Exception err)
                            {
                                Logger.ErrorException("Exception unpacking update,reverting.", err);
                                error = err.Message;
                                foreach (KeyValuePair<string, string> kvp in files)
                                {
                                    if (File.Exists(kvp.Key))
                                    {
                                        if (File.Exists(kvp.Value))
                                            File.Delete(kvp.Value);

                                        File.Move(kvp.Key, kvp.Value);
                                    }
                                }
                                success = false;
                            }
                        }
                    }
                }
                if (UpdateCompleteEvent != null)
                    UpdateCompleteEvent(null, new UpdateCompletedEventArgs(success,error));
            }
        }

        static void cli_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            if (UpdateDownloadProgressChanged != null)
                UpdateDownloadProgressChanged(null, new UpdateDownloadProgressEventArgs(e.ProgressPercentage));
        }


        public class UpdateDownloadProgressEventArgs : EventArgs
        {
            public UpdateDownloadProgressEventArgs(int percent)
            {
                this.Percent = percent;
            }

            public int Percent { get; private set; }
        }
        public class UpdateCompletedEventArgs : EventArgs
        {
            public UpdateCompletedEventArgs(bool success, string error = "")
            {
                this.Success = success;
                this.Error = error;
            }

            public bool Success { get; private set; }
            public string Error { get; private set; }
        }
    }
}
